function PromiseX(executor) {
    let self = this;
    self.status = 'padding';
    self.value = undefined;
    self.reason = undefined;
    self.onFullfieldCb = [];
    self.onrejectedCb = [];

    function resolve(val) {
        if (self.status = 'padding') {
            self.value = val;
            self.status = 'fullfield';
            self.onFullfieldCb.forEach(fn => fn())
        }
    }
    function reject(err) {
        if (self.status = 'padding') {
            self.reason = err;
            self.status = 'rejected';
            self.onrejectedCb.forEach(fn => fn())
        }
    }

    try {
        executor(resolve, reject)
    } catch (err) {
        reject(err)
    }
}

PromiseX.prototype.then = function (onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => { return val }
    onRejected = typeof onRejected === 'function' ? onRejected : val => { return val }
    let promise2
    let self = this
    if (self.status === 'fullfield') {
        promise2 = new PromiseX(function (resolve, reject) {
            setTimeout(function () {
                let x = onFulfilled(self.value)
                resolvePromise(promise2, x, resolve, reject)
            })
        })
    }
    if (self.status === 'rejected') {
        promise2 = new PromiseX(function (resolve, reject) {
            setTimeout(function () {
                let x = onRejected(self.reason)
                resolvePromise(promise2, x, resolve, reject)
            })
        })
    }
    if (self.status === 'padding') {
        promise2 = new PromiseX(function (resolve, reject) {
            onFullfieldCb.push(function () {
                setTimeout(function () {
                    let x = onRejected(self.reason)
                    resolvePromise(promise2, x, resolve, reject)
                })
            })
            onrejectedCb.push(function () {
                setTimeout(function () {
                    let x = onRejected(self.reason)
                    resolvePromise(promise2, x, resolve, reject)
                })
            })
        })
    }
    return promise2
}
PromiseX.prototype.resolve = function (value) {
    return new PromiseX(function (resolve, reject) {
        resolve(value);
    })
}
PromiseX.prototype.reject = function (err) {
    return new PromiseX(function (resolve, reject) {
        reject(err);
    })
}
PromiseX.prototype.catch = function (rejected) {
    return this.then(null, rejected);
}
PromiseX.call = function (proList) {
    return new PromiseX(function (resolve, reject) {
        proList.forEach(function (pro) {
            pro.then(resolve, reject)
        })
    })
}
PromiseX.race = function (proList) {
    let promise4, result = []
    promise4 = new PromiseX(function (resolve, reject) {
        proList.forEach(function (pro, i) {
            if (!!pro && (typeof pro === 'object' || typeof pro === 'function') && typeof pro.then === 'function') {//pro为promise
                pro.then(function (val1) {
                    resolvePromise(promise4, val1, function (val2) {
                        resolve(val2)
                    }, function (err) {
                        reject(err)
                    })
                })
            } else {
                resolve(pro)
            }
        })
    })
    return promise4
}
/**
 * 
 * @param {*} p3 promise 类型
 * @param {*} times 允许失败次数
 */
// PromiseX.retry = function (p3, times) {
//     return new PromiseX(function (resolve, reject) {
//         while (times--) {
//             try {
//                 let result = await p3;
//                 resolve(result);
//                 break;//如果成功则跳出循环
//             } catch (err) {
//                 if (!time) reject(err)
//             }
//         }
//     })
// }
/**
 * 
 * @param {*} promise2 新的promise
 * @param {*} x 上一个then返回的函数
 * @param {*} resolve 成功回调
 * @param {*} reject 失败回调
 */
function resolvePromise(promise2, x, resolve, reject) {
    // 1)不能引用同一个对象 可能会造成死循环
    if (promise2 === x) {
        return reject(new TypeError('[TypeError: Chaining cycle detected for promise #<Promise>]----'));
    }
    let called;// promise的实现可能有多个，但都要遵循promise a+规范，我们自己写的这个promise用不上called,但是为了遵循规范才加上这个控制的，因为别人写的promise可能会有多次调用的情况。
    // 2)判断x的类型，如果x是对象或者函数，说明x有可能是一个promise，否则就不可能是promise
    if ((typeof x === 'object' && x != null) || typeof x === 'function') {
        // 有可能是promise promise要有then方法
        try {
            // 因为then方法有可能是getter来定义的, 取then时有风险，所以要放在try...catch...中
            // 别人写的promise可能是这样的
            // Object.defineProperty(promise, 'then', {
            // 	get() {
            // 		throw new Error();
            // 	}
            // })
            let then = x.then;
            if (typeof then === 'function') { // 只能认为他是promise了
                // x.then(()=>{}, ()=>{}); 不要这么写，以防以下写法造成报错， 而且也可以防止多次取值
                // let obj = {
                // 	a: 1,
                // 	get then() {
                // 		if (this.a++ == 2) {
                // 			throw new Error();
                // 		}
                // 		console.log(1);
                // 	}
                // }
                // obj.then;
                // obj.then

                // 如果x是一个promise那么在new的时候executor就立即执行了，就会执行他的resolve，那么数据就会传递到他的then中
                then.call(x, y => {// 当前promise解析出来的结果可能还是一个promise, 直到解析到他是一个普通值
                    if (called) return;
                    called = true;
                    resolvePromise(promise2, y, resolve, reject);// resolve, reject都是promise2的
                }, r => {
                    if (called) return;
                    called = true;
                    reject(r);
                });
            } else {
                // {a: 1, then: 1} 
                resolve(x);
            }
        } catch (e) {// 取then出错了 有可能在错误中又调用了该promise的成功或则失败
            if (called) return;
            called = true;
            reject(e);
        }
    } else {
        resolve(x);
    }
}

new PromiseX((resolve, reject) => {
    setTimeout(() => {
        resolve({ test: 1 })
        resolve({ test: 2 })
        reject({ test: 2 })
    }, 1000)
}).then((data) => {
    debugger
    console.log('result1', data)
},(data1)=>{
    console.log('result2',data1)
}).then((data) => {
    console.log('result3', data)
}).catch((err=>{
    console.log(err)
}))